package com.exam.api.common.utils;


import cn.hutool.core.collection.ListUtil;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 列表差异处理工具
 *
 * @author bcheng
 */
public class ListDiffUtil {
    /**
     * 查找在 modifiedList 中新增的元素，这些元素不在 originalList 中。
     *
     * @param originalList 原始列表
     * @param modifiedList 修改后的列表
     * @param idExtractor  提取元素 ID 的函数
     * @param <T>          列表元素类型
     * @param <ID>         元素 ID 类型
     * @return 新增元素列表
     */
    public static <T, ID> List<T> findAdded(Collection<T> originalList, Collection<T> modifiedList, Function<T, ID> idExtractor) {
        originalList = originalList == null ? ListUtil.empty() : originalList;
        modifiedList = modifiedList == null ? ListUtil.empty() : modifiedList;
        // 创建一个 List 存储原始列表中元素的 ID 与其对应元素的关系
        List<ID> originalIds = originalList.stream().map(idExtractor).toList();

        // 过滤 modifiedList 中不在 originalIds 中的元素（即新增元素）
        return modifiedList.stream()
                .filter(modifiedItem -> !originalIds.contains(idExtractor.apply(modifiedItem)))
                .collect(Collectors.toList());
    }

    /**
     * 查找在 modifiedList 中更新的元素，这些元素在 originalList 中存在且具有相同的 ID。
     *
     * @param originalList 原始列表
     * @param modifiedList 修改后的列表
     * @param idExtractor  提取元素 ID 的函数
     * @param <T>          列表元素类型
     * @param <ID>         元素 ID 类型
     * @return 更新元素列表
     */
    public static <T, ID> List<T> findUpdated(Collection<T> originalList, Collection<T> modifiedList, Function<T, ID> idExtractor) {
        originalList = originalList == null ? ListUtil.empty() : originalList;
        modifiedList = modifiedList == null ? ListUtil.empty() : modifiedList;
        // 创建一个 List 存储修改后列表中元素的 ID 与其对应元素的关系
        List<ID> originalIds = originalList.stream().map(idExtractor).toList();

        // 过滤原始列表中在 modifiedIds 中存在的元素（即更新元素）
        return modifiedList.stream()
                .filter(modifiedItem -> originalIds.contains(idExtractor.apply(modifiedItem)))
                .collect(Collectors.toList());
    }

    /**
     * 查找在 originalList 中被删除的元素，这些元素不在 modifiedList 中。
     *
     * @param originalList 原始列表
     * @param modifiedList 修改后的列表
     * @param idExtractor  提取元素 ID 的函数
     * @param <T>          列表元素类型
     * @param <ID>         元素 ID 类型
     * @return 删除元素列表
     */
    public static <T, ID> List<T> findDeleted(Collection<T> originalList, Collection<T> modifiedList, Function<T, ID> idExtractor) {
        originalList = originalList == null ? ListUtil.empty() : originalList;
        modifiedList = modifiedList == null ? ListUtil.empty() : modifiedList;
        // 创建一个 List 存储修改后列表中元素的 ID 与其对应元素的关系
        List<ID> modifiedIds = modifiedList.stream().map(idExtractor).toList();

        // 过滤原始列表中不在 modifiedIds 中的元素（即删除元素）
        return originalList.stream()
                .filter(originalItem -> !modifiedIds.contains(idExtractor.apply(originalItem)))
                .collect(Collectors.toList());
    }


    public static void main(String[] args) {
        // 创建两个列表
        List<User> originalList = List.of(
                new User(1, "Alice"),
                new User(2, "Bob"),
                new User(3, "Charlie")
        );
        List<User> modifiedList = List.of(
                new User(2, "Bob"),
                new User(null, "David"),
                new User(null, "Eve")
        );

        // 查找新增元素
        List<User> added = findAdded(originalList, modifiedList, User::getId);
        System.out.println("新增元素：" + added);

        // 查找更新元素
        List<User> updated = findUpdated(originalList, modifiedList, User::getId);
        System.out.println("更新元素：" + updated);

        // 查找删除元素
        List<User> deleted = findDeleted(originalList, modifiedList, User::getId);
        System.out.println("删除元素：" + deleted);
    }

    @Data
    @AllArgsConstructor
    private static class User {
        private Integer id;
        private String name;
    }
}
